from typing import List, Dict, Any, Optional, Union
from sqlalchemy import and_, or_
from sqlalchemy.orm.query import Query
from enum import Enum

class ConditeOperator(Enum):
    _and = "and"
    _or = "or"

class QueryFilter:
    def __init__(self, query: Query):
        self.query = query
        self.conditions = []

    def exact_match(self, **kwargs) -> 'QueryFilter':
        """精确匹配多个字段"""
        for field, value in kwargs.items():
            if value is not None:
                self.conditions.append(getattr(self.query.column_descriptions[0]['entity'], field) == value)
        return self

    def fuzzy_match(self, fields: List[str], keyword: str) -> 'QueryFilter':
        """模糊匹配多个字段"""
        if keyword:
            fuzzy_conditions = []
            for field in fields:
                fuzzy_conditions.append(
                    getattr(self.query.column_descriptions[0]['entity'], field).ilike(f'%{keyword}%')
                )
            if fuzzy_conditions:
                self.conditions.append(or_(*fuzzy_conditions))
        return self

    def range_filter(self, field: str, min_val: Any = None, max_val: Any = None) -> 'QueryFilter':
        """范围过滤"""
        model_field = getattr(self.query.column_descriptions[0]['entity'], field)
        if min_val is not None:
            self.conditions.append(model_field >= min_val)
        if max_val is not None:
            self.conditions.append(model_field <= max_val)
        return self

    def in_filter(self, field: str, values: List[Any]) -> 'QueryFilter':
        """IN 查询"""
        if values:
            self.conditions.append(
                getattr(self.query.column_descriptions[0]['entity'], field).in_(values)
            )
        return self

    def apply_filters(self, condite_operate = ConditeOperator._and.value) -> Query:
        """应用所有过滤条件"""
        if self.conditions:
            if condite_operate == ConditeOperator._and.value:
                return self.query.filter(and_(*self.conditions))
            elif condite_operate == ConditeOperator._and.value:
                return self.query.filter(or_(*self.conditions))
        return self.query